home *** CD-ROM | disk | FTP | other *** search
/ CD World Haziran 1997 / CD World Haziran 1997.iso / Cesitlemeler / Directx 3.0 / dx3.exe / SDK / SAMPLES / DUEL / GAMEPROC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-09  |  51.1 KB  |  1,986 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved.
  4.  *
  5.  *  File:       gameproc.c
  6.  *  Content:    Game processing code
  7.  *
  8.  *
  9.  ***************************************************************************/
  10. #include "gameproc.h"
  11. #include "util.h"
  12. #include "gfx.h"
  13. #include "comm.h"
  14. #include "input.h"
  15. #include "lobby.h"
  16. #include "wizard.h"
  17. #include "dsound.h"
  18. #include "sfx.h"
  19. #include "stdio.h"
  20.  
  21. /*
  22.  * Externals
  23.  */
  24. extern DWORD                    gdwKeys;
  25. extern LPDIRECTDRAWSURFACE      glpShip0;
  26. extern LPDIRECTDRAWSURFACE      glpShip1;
  27. extern LPDIRECTDRAWSURFACE      glpShip2;
  28. extern LPDIRECTDRAWSURFACE      glpShip3;
  29. extern BOOL                     gbShowFrameCount;
  30. extern LPDIRECTDRAWSURFACE      glpNum;
  31. extern BOOL                     gbIsHost;
  32. extern BOOL                     gbIsActive;
  33. extern LPDPSESSIONDESC2         glpdpSD;
  34. extern HWND                     ghWndMain;
  35. extern HINSTANCE                ghinst;
  36. extern BOOL                     gbReliable;
  37.  
  38. /*
  39.  * Globals
  40.  */
  41. FRAG                            gFrags[64];                 // ship framents
  42. BLOCKS                          gBlocks;                    // field layout
  43. LPVOID                          glpvReceiveBuffer = NULL;   // buffer to store received messages
  44. DWORD                           gdwReceiveBufferSize = 0;   // size of buffer
  45. DPID                            gOurID;                     // our player id
  46. BOOL                            gbHaveHostInit;             // do we need to do host initializaton
  47. int                             gnProgramState;             // current state of the game
  48. DWORD                           gdwFrameCount;              // used for fps calc
  49. DWORD                           gdwFramesLast;              // ..
  50. DWORD                           gdwFrameTime;               // ..
  51. BOOL                            gbUpdate;                   // TRUE if player data needs to be updated
  52. BOOL                            gbNoField;                  // display blocks ?
  53. BOOL                            gbSessionLost;              // did we get disconnected ?
  54. HOSTMSG                         gHostMsg;                   // message buffer
  55. BLOCKHITMSG                     gBlockHitMsg;               // ..
  56. SHIPHITMSG                      gShipHitMsg;                // ..
  57. ADDBLOCKMSG                     gAddBlockMsg;               // ..
  58. CONTROLMSG                      gControlMsg;                // .. 
  59. SYNCMSG                         gSyncMsg;                   // ..
  60. TCHAR                           gDebugBuff[MAX_ERRORMSG];   // buffer for debug output
  61.  
  62. /*
  63.  * Statics
  64.  */
  65.  
  66. static double      gDirx[40] =                          
  67. {
  68.     0.000000,
  69.     0.156434,
  70.     0.309017,
  71.     0.453991,
  72.     0.587785,
  73.     0.707107,
  74.     0.809017,
  75.     0.891007,
  76.     0.951057,
  77.     0.987688,
  78.     1.000000,
  79.     0.987688,
  80.     0.951057,
  81.     0.891007,
  82.     0.809017,
  83.     0.707107,
  84.     0.587785,
  85.     0.453990,
  86.     0.309017,
  87.     0.156434,
  88.     0.000000,
  89.     -0.156435,
  90.     -0.309017,
  91.     -0.453991,
  92.     -0.587785,
  93.     -0.707107,
  94.     -0.809017,
  95.     -0.891007,
  96.     -0.951057,
  97.     -0.987688,
  98.     -1.000000,
  99.     -0.987688,
  100.     -0.951056,
  101.     -0.891006,
  102.     -0.809017,
  103.     -0.707107,
  104.     -0.587785,
  105.     -0.453990,
  106.     -0.309017,
  107.     -0.156434
  108. };
  109.  
  110. static double      gDiry[40] =
  111. {
  112.     -1.000000,
  113.     -0.987688,
  114.     -0.951057,
  115.     -0.891007,
  116.     -0.809017,
  117.     -0.707107,
  118.     -0.587785,
  119.     -0.453990,
  120.     -0.309017,
  121.     -0.156434,
  122.     0.000000,
  123.     0.156434,
  124.     0.309017,
  125.     0.453991,
  126.     0.587785,
  127.     0.707107,
  128.     0.809017,
  129.     0.891007,
  130.     0.951057,
  131.     0.987688,
  132.     1.000000,
  133.     0.987688,
  134.     0.951057,
  135.     0.891006,
  136.     0.809017,
  137.     0.707107,
  138.     0.587785,
  139.     0.453990,
  140.     0.309017,
  141.     0.156434,
  142.     0.000000,
  143.     -0.156435,
  144.     -0.309017,
  145.     -0.453991,
  146.     -0.587785,
  147.     -0.707107,
  148.     -0.809017,
  149.     -0.891007,
  150.     -0.951057,
  151.     -0.987688
  152. };
  153.  
  154. /*
  155.  * InitMessageBuffers
  156.  *
  157.  * Sets up buffes used for sending different types of messages
  158.  */
  159. void InitMessageBuffers(void)
  160. {
  161.     gHostMsg.byType        = MSG_HOST;
  162.     gBlockHitMsg.byType    = MSG_BLOCKHIT;
  163.     gShipHitMsg.byType     = MSG_SHIPHIT;    
  164.     gAddBlockMsg.byType    = MSG_ADDBLOCK;
  165.     gControlMsg.byType     = MSG_CONTROL; 
  166.     gSyncMsg.byType        = MSG_SYNC;
  167. }
  168.  
  169. /*
  170.  * LaunchGame
  171.  *
  172.  * Sets up the game layout and launches
  173.  */
  174. void LaunchGame(void)
  175. {
  176.     HRESULT hr;
  177.  
  178.     // initialize global message buffers
  179.     InitMessageBuffers();
  180.  
  181.     // update window title
  182.     UpdateTitle();
  183.  
  184.     // get current session description (glpdpSD is initialized in here)
  185.     hr = DPlayGetSessionDesc();
  186.     if (FAILED(hr) || (!glpdpSD))
  187.     {
  188.         ShowError(IDS_DPLAY_ERROR_GSD);
  189.         goto ABORT;
  190.     }
  191.  
  192.     // initialize random number seed
  193.     srand((int)GetTickCount());
  194.  
  195.     // clear front buffer before changing palette
  196.     EraseScreen();
  197.     FlipScreen();
  198.  
  199.     // initialize us
  200.     hr = InitOurShip();
  201.     if (FAILED(hr))
  202.     {
  203.         goto ABORT;
  204.     }
  205.  
  206.     // get the field layout
  207.     if( gbIsHost )
  208.     {
  209.         // initialize field (done only by host)
  210.         if (!gbNoField)
  211.             InitField();
  212.  
  213.         // we have host initialization
  214.         gbHaveHostInit = TRUE;
  215.  
  216.         // start updating screen
  217.         gbIsActive = TRUE;
  218.     }
  219.     else
  220.     {
  221.         // get it from host, if we are joining
  222.         gbHaveHostInit = FALSE;
  223.     }
  224.  
  225.     // success
  226.     return;
  227.  
  228. ABORT:
  229.     // something went wrong, terminate game
  230.     ExitGame();
  231. }
  232.  
  233. /*
  234.  * ExitGame
  235.  *
  236.  * Game termination code
  237.  */
  238. void ExitGame(void)
  239. {
  240.     // shut down app
  241.     PostMessage( ghWndMain, WM_CLOSE, 0, 0 );
  242. }
  243.  
  244. /*
  245.  * InitOurShip
  246.  *
  247.  * Initializes our ship's initial attributes
  248.  */
  249. HRESULT InitOurShip(void)
  250. {
  251.     int i;
  252.     SHIP ship;
  253.     HRESULT hr;
  254.  
  255.     // wipe out everything
  256.     ZeroMemory(&ship, sizeof(ship));
  257.  
  258.     // initialize sound buffers
  259.     InitPlayerLocalSoundData(&ship);
  260.  
  261.     // calculate ship type based on the number of players in the game
  262.     // we cycle through four ships (Y,R,G,B) for now.
  263.  
  264.     ship.byType = (BYTE) ((glpdpSD->dwCurrentPlayers-1) % NUM_SHIP_TYPES);
  265.     ship.dPosX  = randInt(0,MAX_SHIP_X);
  266.     ship.dPosY  = randInt(0,MAX_SHIP_Y);
  267.     ship.cFrame = randInt(0, MAX_SHIP_FRAME);
  268.     ship.bEnable = TRUE;
  269.  
  270.     // set our local data
  271.     hr = DPlaySetPlayerData(gOurID, &ship, sizeof(ship), DPSET_LOCAL);
  272.     if (FAILED(hr))
  273.     {
  274.         ShowError(IDS_DPLAY_ERROR_SPLD);
  275.         goto FAIL;
  276.     }
  277.  
  278.     // no ship fragments
  279.     for(i=0; i<64; i++)
  280.         gFrags[i].valid = FALSE;
  281.  
  282.     // success
  283.     return DP_OK;
  284.  
  285. FAIL:
  286.     // failed
  287.     return hr;
  288. }
  289.  
  290. /*
  291.  *FUNCTION:   InitPlayerLocalSoundData
  292.  *
  293.  *
  294.  *NOTES:      Takes a ship and initializes ONLY its soundbuffers and sound flags.
  295.  *            It leaves everything else alone.  Good for when going to
  296.  *            full-screen mode, when we need to get rid of the sound buffers
  297.  *            for a bit, but don't want to change the data.
  298.  */
  299. void InitPlayerLocalSoundData(LPSHIP lpShip)
  300. {
  301. int i;
  302.     if (gbSoundInitialized)
  303.     {
  304.         for (i=0; i<MAX_SOUNDS; i++)
  305.         {
  306.             if (FALSE == WaveGetBuffers(gSoundEffect[i],&lpShip->lpDirectSoundBuffer[i], &lpShip->lpDirectSound3DBuffer[i]))
  307.             {//if it didn't work, get rid of all the other sound buffers
  308.                 ShowError(IDS_DSOUND_DUPBUF);
  309.                 for (--i; i>=0; i--)
  310.                 {
  311.                     IDirectSoundBuffer_Release(lpShip->lpDirectSoundBuffer  [i]);
  312.                     IDirectSoundBuffer_Release(lpShip->lpDirectSound3DBuffer[i]);
  313.                     lpShip->lpDirectSoundBuffer  [i] = NULL;
  314.                     lpShip->lpDirectSound3DBuffer[i] = NULL;
  315.                 }
  316.                 return;
  317.             }
  318.         }
  319.  
  320.         lpShip->bFiring        = FALSE;
  321.         lpShip->bBounced       = FALSE;
  322.         lpShip->bDeath         = FALSE;
  323.         lpShip->bBlockHit      = FALSE;
  324.         lpShip->bEngineRunning = FALSE;
  325.         lpShip->bMoving        = FALSE;
  326.     }
  327.     else
  328.     {
  329.     //if sound initialization has already failed in InitSfx(), then we want the ships'
  330.     //sound buffers to be NULL so that we don't try to release them later.
  331.         for (i=0; i<MAX_SOUNDS; i++)
  332.         {
  333.             lpShip->lpDirectSoundBuffer  [i] = NULL;
  334.             lpShip->lpDirectSound3DBuffer[i] = NULL;
  335.         }
  336.     }
  337. };
  338.  
  339. /*
  340.  *FUNCTION:   SetPlayerLocalSoundDataCB (CALLBACK)
  341.  *
  342.  *PURPOSE:    Initializes and registers a player's local SOUND data ONLY.
  343.  */
  344. BOOL WINAPI SetPlayerLocalSoundDataCB(DPID dpId, DWORD dwPlayerType, LPCDPNAME lpName, 
  345.                                       DWORD dwFlags, LPVOID lpContext)
  346. {
  347.     SHIP ship;
  348.     DWORD dwSize = sizeof(ship);
  349.     HRESULT hr;
  350.  
  351.     DPlayGetPlayerData(dpId, &ship, &dwSize, DPGET_LOCAL); 
  352.  
  353.     // no player data yet
  354.     if (0 == dwSize)
  355.         return TRUE;
  356.  
  357.     InitPlayerLocalSoundData(&ship);
  358.  
  359.     hr = DPlaySetPlayerData(dpId, &ship, dwSize, DPSET_LOCAL);
  360.     return (DP_OK == hr);
  361. };
  362.  
  363. /*
  364.  *FUNCTION:   InitLocalSoundData
  365.  *
  366.  *PURPOSE:    Initializes and registers all players' sound data ONLY
  367.  */
  368. HRESULT InitLocalSoundData(void)
  369. {
  370.     HRESULT hr;
  371.     hr = DPlayEnumPlayers(&(glpdpSD->guidInstance), SetPlayerLocalSoundDataCB, NULL, 0);
  372.     return hr;
  373. }
  374.  
  375. /*
  376.  *FUNCTION:   ReleaseLocalSoundData
  377.  *
  378.  *NOTES:      Releases a single ship's local sound buffers.
  379.  */
  380. void ReleasePlayerLocalSoundData(LPSHIP lpShip)
  381. {
  382. int i;
  383.  
  384.     if (gbSoundInitialized)
  385.     {
  386.         for (i=0; i<MAX_SOUNDS; i++)
  387.         {
  388.             if (lpShip->lpDirectSoundBuffer[i] != NULL)
  389.             {
  390.                 IDirectSoundBuffer_Stop     (lpShip->lpDirectSoundBuffer[i]);
  391.                 IDirectSoundBuffer_Release  (lpShip->lpDirectSoundBuffer[i]);
  392.                 lpShip->lpDirectSoundBuffer[i] = NULL;
  393.             }
  394.  
  395.             if (lpShip->lpDirectSound3DBuffer[i] != NULL)
  396.             {
  397.                 IDirectSound3DBuffer_Release(lpShip->lpDirectSound3DBuffer[i]); 
  398.                 lpShip->lpDirectSound3DBuffer[i] = NULL;
  399.             }
  400.         }
  401.     }
  402. };
  403.  
  404. /*
  405.  *FUNCTION:   ReleasePlayerLocalData  (CALLBACK)
  406.  *
  407.  *PURPOSE:    Retrieves and releases a player's local data from dplay.
  408.  */
  409. BOOL WINAPI ReleasePlayerLocalDataCB(DPID dpId, DWORD dwPlayerType, LPCDPNAME lpName,
  410.                                      DWORD dwFlags, LPVOID lpContext)
  411. {
  412.     SHIP ship;
  413.     DWORD dwSize = sizeof(SHIP);    
  414.     HRESULT hr;
  415.     
  416.     hr = DPlayGetPlayerData(dpId, &ship, &dwSize, DPGET_LOCAL);
  417.     if (FAILED(hr))
  418.     {
  419.         wsprintf(gDebugBuff, TEXT("Get Player local data failed for id %d\n"), dpId);
  420.         DEBUG_OUT(gDebugBuff);
  421.         goto FAIL;
  422.     }
  423.  
  424.     // no player data yet
  425.     if (0 == dwSize)
  426.         return TRUE;
  427.  
  428.     ReleasePlayerLocalSoundData(&ship);
  429.  
  430.     hr = DPlaySetPlayerData(dpId, &ship,  dwSize, DPSET_LOCAL);
  431.     if (FAILED(hr))
  432.     {
  433.         ShowError(IDS_DPLAY_ERROR_SPLD);
  434.         goto FAIL;
  435.     }
  436.  
  437.     // success
  438.     return TRUE;
  439. FAIL:
  440.     // we failed
  441.     return FALSE;
  442. }
  443.  
  444. /*
  445.  *FUNCTION:   ReleaseLocalData
  446.  *
  447.  *PURPOSE:    Releases local data of ALL players.
  448.  */
  449. void ReleaseLocalData(void)
  450. {
  451.      HRESULT hr;
  452.  
  453.      if (gnProgramState == PS_ACTIVE)
  454.      {
  455.          hr = DPlayEnumPlayers(&(glpdpSD->guidInstance), ReleasePlayerLocalDataCB, NULL, 0);
  456.          if (FAILED(hr))
  457.          {
  458.              ShowError(IDS_DPLAY_ERROR_EP);
  459.          }
  460.      }
  461. };
  462.  
  463. /*
  464.  * ProcessUserInput
  465.  *
  466.  * Processes any input from the user and updates our ship state
  467.  */
  468. void ProcessUserInput(LPSHIP lpShip)
  469. {
  470.     static dwOldKeys = 0;
  471.  
  472.     gbUpdate = FALSE;
  473.  
  474.     // DSOUND: check if the engine was turned off
  475.     if (!(gdwKeys    & (KEY_DOWN | KEY_UP)) && 
  476.         (dwOldKeys & (KEY_DOWN | KEY_UP)))
  477.     {
  478.         gdwKeys |= KEY_ENGINEOFF;
  479.  
  480.         gControlMsg.byState = (BYTE) gdwKeys;
  481.         // let everyone know that we just turned our engine off
  482.         SendGameMessage((LPGENERICMSG) &gControlMsg, DPID_ALLPLAYERS);
  483.     }
  484.  
  485.     // update our ship state
  486.     UpdateState(lpShip, gdwKeys);
  487.  
  488.     // remember current keys for next frame
  489.     dwOldKeys = gdwKeys;
  490. }
  491.  
  492. /*
  493.  * UpdateState
  494.  *
  495.  * Updates the current state of our ship, given user input
  496.  */
  497. void UpdateState(LPSHIP lpShip, DWORD dwControls)
  498. {
  499.     lpShip->dwKeys = dwControls;
  500.  
  501.     if( dwControls & KEY_LEFT )
  502.     {
  503.         gbUpdate = TRUE;
  504.         lpShip->cFrame -= 1;
  505.         if( lpShip->cFrame < 0 )
  506.             lpShip->cFrame += MAX_SHIP_FRAME;
  507.     }
  508.     if( dwControls & KEY_RIGHT )
  509.     {
  510.         gbUpdate = TRUE;
  511.         lpShip->cFrame += 1;
  512.         if( lpShip->cFrame >= MAX_SHIP_FRAME )
  513.             lpShip->cFrame -= MAX_SHIP_FRAME;
  514.     }
  515.     if( dwControls & KEY_UP )
  516.     {
  517.         gbUpdate = TRUE;
  518.         lpShip->dVelX += gDirx[lpShip->cFrame] * 10.0 / 1000.0;
  519.         lpShip->dVelY += gDiry[lpShip->cFrame] * 10.0 / 1000.0;
  520.     }
  521.     if( dwControls & KEY_DOWN )
  522.     {
  523.         gbUpdate = TRUE;
  524.         lpShip->dVelX -= gDirx[lpShip->cFrame] * 10.0 / 1000.0;
  525.         lpShip->dVelY -= gDiry[lpShip->cFrame] * 10.0 / 1000.0;
  526.     }
  527.     if( dwControls & KEY_STOP )
  528.     {
  529.         gbUpdate = TRUE;
  530.         lpShip->dVelX = 0.0;
  531.         lpShip->dVelY = 0.0;
  532.     }
  533.     if( !lpShip->bBulletEnable && lpShip->bEnable )
  534.     {
  535.         if( dwControls & KEY_FIRE )
  536.         {
  537.             gbUpdate = TRUE;
  538.             // launch a new bullet
  539.             lpShip->dBulletPosX = (WORD) (gDirx[lpShip->cFrame]*6.0 + 16.0 + lpShip->dPosX);
  540.             lpShip->dBulletPosY = (WORD) (gDiry[lpShip->cFrame]*6.0 + 16.0 + lpShip->dPosY);
  541.             lpShip->dBulletVelX = gDirx[lpShip->cFrame]*500.0/1000.0;
  542.             lpShip->dBulletVelY = gDiry[lpShip->cFrame]*500.0/1000.0;
  543.             lpShip->bBulletEnable = TRUE;
  544.             lpShip->dwBulletFrame = 0;
  545.         }
  546.     }
  547. }
  548.  
  549. /*
  550.  * SendSync
  551.  *
  552.  * Sends a sync message with the rendevous position. We are using a synchronization technique in
  553.  * which every player informs everyone else where the player is going to be at the end of the 
  554.  * next sync interval. Based on this rendezvous position, everyone tries to move their corresponding
  555.  * ghosts to the rendezvous position by the end of the interval.
  556.  */
  557. void SendSync(LPSHIP lpShip)
  558. {
  559.     gSyncMsg.byShipType = lpShip->byType;
  560.     gSyncMsg.cFrame = lpShip->cFrame;
  561.     gSyncMsg.dPosX  = lpShip->dPosX + lpShip->dVelX*1000;
  562.     gSyncMsg.dPosY  = lpShip->dPosY + lpShip->dVelY*1000;
  563.  
  564.     SendGameMessage((LPGENERICMSG) &gSyncMsg, DPID_ALLPLAYERS);
  565. }
  566.  
  567. /*
  568.  * UpdateDisplayStatus
  569.  *
  570.  * Updates the disable timeout. Enables the ship if disable timeout has elapsed.
  571.  */
  572. void UpdateDisplayStatus(LPSHIP lpShip)
  573. {
  574.     DWORD dwTickDiff;
  575.     DWORD dwTickCount;
  576.  
  577.     // current time
  578.     dwTickCount = timeGetTime();
  579.  
  580.     // time elapsed since last update
  581.     dwTickDiff =  dwTickCount - lpShip->dwLastTick;
  582.  
  583.     // timestamp
  584.     lpShip->dwLastTick = dwTickCount;
  585.  
  586.     // update time-out
  587.     lpShip->iCountDown -= dwTickDiff;
  588.  
  589.     // time-out ?
  590.     if( lpShip->iCountDown < 0 )
  591.     {
  592.         // get new position and enable our lpShip
  593.         lpShip->dPosX = randInt(0,MAX_SHIP_X);
  594.         lpShip->dPosY = randInt(0,MAX_SHIP_Y);
  595.         lpShip->cFrame = randInt(0, MAX_SHIP_FRAME);
  596.         lpShip->bEnable = TRUE;
  597.     }
  598. }
  599.  
  600. /*
  601.  * UpdatePosition
  602.  *
  603.  * Updates our ship's position
  604.  */
  605. void UpdatePosition(DPID dpId, LPSHIP lpShip )
  606. {
  607.     int     x,y;
  608.     BYTE    oldxCell, oldyCell, newxCell, newyCell, mask, col, row;
  609.     double  thisTick, totalTick, xtick, ytick;
  610.     DWORD   dwTickCount;
  611.     DWORD   dwTickDiff;
  612.  
  613.     if( !lpShip->bEnable )
  614.         return;
  615.  
  616.     // how long has it been since we last updated
  617.     dwTickCount = timeGetTime();
  618.     dwTickDiff = dwTickCount - lpShip->dwLastTick;
  619.  
  620.     // current timestamp
  621.     lpShip->dwLastTick = dwTickCount;
  622.  
  623.     oldxCell = (int)(lpShip->dPosX+16.0) >> 4;
  624.     oldyCell = (int)(lpShip->dPosY+16.0) >> 4;
  625.  
  626.     // compute new position
  627.     lpShip->dPosX += lpShip->dVelX * dwTickDiff;
  628.     lpShip->dPosY += lpShip->dVelY * dwTickDiff;
  629.  
  630.     newxCell = (int)(lpShip->dPosX+16.0) >> 4;
  631.     newyCell = (int)(lpShip->dPosY+16.0) >> 4;
  632.     if(oldxCell != newxCell)
  633.     {
  634.         // we allow ghosts to pass through the blocks
  635.         if( (dpId == gOurID) && IsHit( newxCell, newyCell ) )
  636.         {
  637.             if( lpShip->dVelX > 0.0 )
  638.                 lpShip->dPosX = (oldxCell << 4) + 15 - 16;
  639.             else
  640.                 lpShip->dPosX = (oldxCell << 4) - 16;
  641.             lpShip->dVelX = -lpShip->dVelX*0.9;
  642.             newxCell = oldxCell;
  643.             lpShip->bBounced = TRUE;
  644.         }
  645.     }
  646.     if(oldyCell != newyCell)
  647.     {
  648.         // we allow ghosts to pass through the blocks
  649.         if( (dpId == gOurID) && IsHit( newxCell, newyCell ) )
  650.         {
  651.             if( lpShip->dVelY > 0.0 )
  652.                 lpShip->dPosY = (oldyCell << 4) + 15 - 16;
  653.             else
  654.                 lpShip->dPosY = (oldyCell << 4) - 16;
  655.  
  656.             lpShip->dVelY = -lpShip->dVelY*0.9;
  657.             lpShip->bBounced = TRUE;
  658.         }
  659.     }
  660.  
  661.     if( lpShip->dPosX > MAX_SHIP_X )
  662.     {
  663.         lpShip->dPosX = MAX_SHIP_X;
  664.         lpShip->dVelX = -lpShip->dVelX*0.9;
  665.         lpShip->bBounced = TRUE;
  666.     }
  667.     else if ( lpShip->dPosX < 0 )
  668.     {
  669.         lpShip->dPosX =0;
  670.         lpShip->dVelX = -lpShip->dVelX*0.9;
  671.         lpShip->bBounced = TRUE;
  672.     }
  673.     if( lpShip->dPosY > MAX_SHIP_Y )
  674.     {
  675.         lpShip->dPosY = MAX_SHIP_Y;
  676.         lpShip->dVelY = -lpShip->dVelY*0.9;
  677.         lpShip->bBounced = TRUE;
  678.     }
  679.     else if ( lpShip->dPosY < 0 )
  680.     {
  681.         lpShip->dPosY =0;
  682.         lpShip->dVelY = -lpShip->dVelY*0.9;
  683.         lpShip->bBounced = TRUE;
  684.     }    
  685.  
  686.     if ((dpId == gOurID) && lpShip->bBounced)
  687.     {
  688.         SendSync(lpShip);
  689.     }
  690.  
  691.     if( !lpShip->bBulletEnable )
  692.         return;
  693.  
  694.     // update the active bullet
  695.     lpShip->dwBulletFrame += dwTickDiff;
  696.     if( lpShip->dwBulletFrame >= MAX_BULLET_FRAME )
  697.     {
  698.         lpShip->bFiring = FALSE;
  699.         lpShip->bBulletEnable = FALSE;
  700.         return;
  701.     }
  702.  
  703.  
  704.     if( lpShip->dBulletVelX != 0.0 )
  705.         xtick = 8.0/lpShip->dBulletVelX;
  706.     else
  707.         xtick = 999999.0;
  708.  
  709.     if( lpShip->dBulletVelY != 0.0 )
  710.         ytick = 8.0/lpShip->dBulletVelY;
  711.     else
  712.         ytick = 999999.0;
  713.  
  714.     if( xtick < 0.0 )
  715.         xtick = -xtick;
  716.     if( ytick < 0.0 )
  717.         ytick = -ytick;
  718.  
  719.     if( xtick < ytick )
  720.         thisTick = xtick;
  721.     else
  722.         thisTick = ytick;
  723.     
  724.     if( thisTick > dwTickDiff )
  725.         thisTick = dwTickDiff;
  726.             
  727.     for( totalTick = 0.0; totalTick < dwTickDiff; )
  728.     {
  729.         totalTick += thisTick;
  730.  
  731.         lpShip->dBulletPosX += lpShip->dBulletVelX * thisTick;
  732.         lpShip->dBulletPosY += lpShip->dBulletVelY * thisTick;
  733.  
  734.         if( lpShip->dBulletPosX > MAX_BULLET_X )
  735.         {
  736.             lpShip->dBulletPosX = MAX_BULLET_X;
  737.             lpShip->dBulletVelX = -lpShip->dBulletVelX*0.9;
  738.         }
  739.         else if ( lpShip->dBulletPosX < 0 )
  740.         {
  741.             lpShip->dBulletPosX =0;
  742.             lpShip->dBulletVelX = -lpShip->dBulletVelX*0.9;
  743.         }
  744.         if( lpShip->dBulletPosY > MAX_BULLET_Y )
  745.         {
  746.             lpShip->dBulletPosY = MAX_BULLET_Y;
  747.             lpShip->dBulletVelY = -lpShip->dBulletVelY*0.9;
  748.         }
  749.         else if ( lpShip->dBulletPosY < 0 )
  750.         {
  751.             lpShip->dBulletPosY =0;
  752.             lpShip->dBulletVelY = -lpShip->dBulletVelY*0.9;
  753.         }
  754.     
  755.         // check to see if it hit anything
  756.         x = (int)(lpShip->dBulletPosX + 0.5) + 1;
  757.         y = (int)(lpShip->dBulletPosY + 0.5) + 1;
  758.     
  759.         row = y >> 4;
  760.         col = x >> 4;
  761.         mask = 1 << (col & 0x7);
  762.         col = col >> 3;
  763.         if( gBlocks.bits[row][col] & mask )
  764.         {
  765.             // dwScored a block hit
  766.             gBlockHitMsg.byRow = row;
  767.             gBlockHitMsg.byCol = col;
  768.             gBlockHitMsg.byMask = mask;
  769.             SendGameMessage((LPGENERICMSG) &gBlockHitMsg, DPID_ALLPLAYERS);
  770.  
  771.             gBlocks.bits[row][col] &= ~mask;
  772.             lpShip->dwScore += 10;
  773.             lpShip->bBulletEnable = FALSE;
  774.             lpShip->bBlockHit = TRUE;
  775.             lpShip->bFiring   = FALSE;
  776.         }
  777.     }
  778. }
  779.  
  780.  
  781. /*
  782.  * IsHit
  783.  *
  784.  * Tells if there is a block at (x,y) location
  785.  */
  786. BOOL IsHit( int x, int y )
  787. {
  788.     int col, mask;
  789.     
  790.     // outside screen boundaries?
  791.     if( (x < 0) || (y < 0) || (x >= 40) || (y >= 30) )
  792.         return TRUE;
  793.     
  794.     // look at the block bits
  795.     mask = 1 << (x & 0x7);
  796.     col = x >> 3;
  797.     if( gBlocks.bits[y][col] & mask )
  798.         return TRUE;
  799.     else
  800.         return FALSE;
  801. }
  802.  
  803. /*
  804.  * InitField
  805.  *
  806.  * Initializes block positions on the field
  807.  */
  808. void InitField(void)
  809. {
  810.     int i, x, y;
  811.     
  812.     // clear all gBlocks
  813.     for(x=0; x<5; x++)
  814.         for(y=0; y<30; y++)
  815.             gBlocks.bits[y][x] = 0;
  816.  
  817.     // set random gBlocks
  818.     for(i=0; i<400; i++)
  819.     {
  820.         x = randInt(0, 40);
  821.         y = randInt(0, 30);
  822.         if( !setBlock(x, y) ) i--;
  823.     }
  824. }
  825.  
  826. /*
  827.  * AddBlock
  828.  *
  829.  * Adds a block to the field
  830.  */
  831. void AddBlock(void)
  832. {
  833.     int x,y;
  834.  
  835.     // maybe add a block?
  836.     if(gbIsHost && gbIsActive && ( randInt( 0, 100 ) > 98 ))
  837.     {
  838.         x = randInt( 0, 40);
  839.         y = randInt( 0, 30);
  840.         if( setBlock( x, y) )
  841.         {
  842.             gAddBlockMsg.byX    = (BYTE) x;
  843.             gAddBlockMsg.byY    = (BYTE) y;
  844.             SendGameMessage((LPGENERICMSG) &gAddBlockMsg, DPID_ALLPLAYERS);
  845.         }
  846.     }
  847. }
  848.  
  849. /*
  850.  * setBlock
  851.  *
  852.  * Turns on a block
  853.  */
  854. BOOL setBlock( int x, int y )
  855. {
  856.     BYTE  mask, col;
  857.  
  858.     mask = 1 << (x & 0x7);
  859.     col = x >> 3;
  860.     
  861.     // is Block already set?
  862.     if( gBlocks.bits[y][col] & mask )
  863.         return FALSE;
  864.     
  865.     // set the block and return success
  866.     gBlocks.bits[y][col] |= mask;
  867.     return TRUE;
  868. }
  869.  
  870. /*
  871.  * AddFrag
  872.  *
  873.  * Turns on a fragment
  874.  */
  875. void AddFrag(LPSHIP lpShip, int offX, int offY)
  876. {
  877.     int i;
  878.     for(i=0; i<64; i++) // find available fragment
  879.     {
  880.         if( !gFrags[i].valid )
  881.         break;
  882.     }
  883.     if( i == 64 )
  884.         return;
  885.     
  886.     
  887.     gFrags[i].dPosX = offX + lpShip->dPosX;
  888.     gFrags[i].dPosY = offY + lpShip->dPosY;
  889.     switch( lpShip->byType )
  890.     {
  891.     case 0: gFrags[i].surf = glpShip0;    break;
  892.     case 1: gFrags[i].surf = glpShip1;    break;
  893.     case 2: gFrags[i].surf = glpShip2;    break;
  894.     case 3: gFrags[i].surf = glpShip3;    break;
  895.     default: DEBUG_OUT(TEXT("Unknown ship type\n")); return;
  896.     }
  897.     gFrags[i].src.top = 32 * ( (int)lpShip->cFrame / 10 ) + offX;
  898.     gFrags[i].src.left = 32 * ( (int)lpShip->cFrame % 10 ) + offY;
  899.     gFrags[i].src.right = gFrags[i].src.left + 8;
  900.     gFrags[i].src.bottom = gFrags[i].src.top + 8;
  901.     gFrags[i].dVelX = ((double)offX - 12.0)/24.0;
  902.     gFrags[i].dVelY = ((double)offY - 12.0)/24.0;
  903.     gFrags[i].valid = TRUE;
  904. }
  905.  
  906. /*
  907.  * UpdateFragment
  908.  *
  909.  * Updates the position of a fragment
  910.  */
  911. void UpdateFragment(int i)
  912. {
  913.     DWORD   dwTickCount;
  914.     static DWORD   dwTickDiff;
  915.     static DWORD dwLastTick;
  916.  
  917.     if( i == 0)
  918.     {
  919.         dwTickCount = timeGetTime();
  920.         dwTickDiff = dwTickCount - dwLastTick;
  921.         dwLastTick = dwTickCount;
  922.     }
  923.     
  924.     if( !gFrags[i].valid )
  925.         return;
  926.     
  927.     gFrags[i].dPosX += (int) (gFrags[i].dVelX * dwTickDiff);
  928.     gFrags[i].dPosY += (int) (gFrags[i].dVelY * dwTickDiff);
  929.     if( (gFrags[i].dPosX < 0.0) || (gFrags[i].dPosX >= 632.0) ||
  930.         (gFrags[i].dPosY < 0.0) || (gFrags[i].dPosY >= 472.0) )
  931.     {
  932.         gFrags[i].valid = FALSE;
  933.     }
  934. }
  935.  
  936. /*
  937.  * DestroyShip
  938.  *
  939.  * Renders a bunch of fragments to show that the ship is destroyed
  940.  */
  941. void DestroyShip( LPSHIP lpShip )
  942. {
  943.     // Set flag for explosion sound
  944.     lpShip->bDeath  = TRUE;
  945.  
  946.     // add ship fragments
  947.     AddFrag(lpShip, 0, 0);
  948.     AddFrag(lpShip, 8, 0);
  949.     AddFrag(lpShip, 16, 0);
  950.     AddFrag(lpShip, 24, 0);
  951.     AddFrag(lpShip, 0, 8);
  952.     AddFrag(lpShip, 8, 8);
  953.     AddFrag(lpShip, 16, 8);
  954.     AddFrag(lpShip, 24, 8);
  955.     AddFrag(lpShip, 0, 16);
  956.     AddFrag(lpShip, 8, 16);
  957.     AddFrag(lpShip, 16, 16);
  958.     AddFrag(lpShip, 24, 16);
  959.     AddFrag(lpShip, 0, 24);
  960.     AddFrag(lpShip, 8, 24);
  961.     AddFrag(lpShip, 16, 24);
  962.     AddFrag(lpShip, 24, 24);
  963.  
  964.     // Play explosion sound
  965.     ProcessSoundFlags(lpShip);
  966. }
  967.  
  968. /*
  969.  * UpdateFrame
  970.  *
  971.  * Refreshes the screen
  972.  */
  973. BOOL UpdateFrame( void )
  974. {
  975.     int i;
  976.     DWORD dwTickCount;
  977.     SHIP  ship;
  978.     DWORD dwSize;
  979.     HRESULT hr;
  980.     static dwSyncLastTick = 0;
  981.     static dwUpdateLastTick = 0;
  982.     
  983.     switch( gnProgramState )
  984.     {
  985.     case PS_ACTIVE:
  986.         // DINPUT: use DirectInput to read game-play keys
  987.         DI_ReadKeys();
  988.  
  989.         // get our local data
  990.         dwSize = sizeof(ship);
  991.         hr = DPlayGetPlayerData(gOurID, &ship, &dwSize, DPGET_LOCAL);
  992.         if (FAILED(hr))
  993.         {
  994.             wsprintf(gDebugBuff, TEXT("Get Player local data failed for id %d\n"), gOurID);
  995.             DEBUG_OUT(gDebugBuff);
  996.             goto FAIL;
  997.         }
  998.  
  999.         if (!ship.bEnable)
  1000.         {
  1001.             // update disable timeout and display status
  1002.             UpdateDisplayStatus(&ship);
  1003.         }
  1004.         else
  1005.         {
  1006.             // process any change in game controls 
  1007.             ProcessUserInput(&ship);
  1008.  
  1009.             dwTickCount = timeGetTime();
  1010.  
  1011.             // synchronize if it's time
  1012.             if (gbIsActive && ((dwTickCount - dwSyncLastTick) > SYNC_INTERVAL))
  1013.             {
  1014.                 SendSync(&ship);
  1015.                 dwSyncLastTick = dwTickCount;
  1016.             }
  1017.  
  1018.             // if our player changed any keys, let everyone know
  1019.             if (gbUpdate)
  1020.             {
  1021.                 // control the number of packets we send
  1022.                 if ((dwTickCount - dwUpdateLastTick) > UPDATE_INTERVAL)
  1023.                 {
  1024.                     // let others know
  1025.                     gControlMsg.byState = (BYTE) gdwKeys;
  1026.                     SendGameMessage((LPGENERICMSG) &gControlMsg, DPID_ALLPLAYERS);
  1027.                     dwUpdateLastTick = dwTickCount;
  1028.                 }
  1029.             }
  1030.         }
  1031.  
  1032.         // save ship data as RenderPlayerCB reads stored data
  1033.         hr = DPlaySetPlayerData(gOurID, &ship, sizeof(ship), DPSET_LOCAL);
  1034.         if (FAILED(hr))
  1035.         {
  1036.             ShowError(IDS_DPLAY_ERROR_SPLD);
  1037.             goto FAIL;
  1038.         }   
  1039.  
  1040.         // update fragments
  1041.         for(i=0; i<64; i++)
  1042.             UpdateFragment(i);
  1043.  
  1044.         // add a block
  1045.         if (!gbNoField)
  1046.             AddBlock();
  1047.  
  1048.         // render everything        
  1049.         if (!DrawScreen())
  1050.         {
  1051.             goto FAIL;
  1052.         }
  1053.         break;
  1054.  
  1055.     case PS_REST:
  1056.         if( gbHaveHostInit )
  1057.         {
  1058.             SetGamePalette();
  1059.             gnProgramState = PS_ACTIVE;
  1060.         }
  1061.         break;
  1062.     }
  1063.  
  1064.     // success
  1065.     return TRUE;
  1066.  
  1067. FAIL:
  1068.     // failed
  1069.     return FALSE;
  1070. }
  1071.  
  1072. /*
  1073.  *FUNCTION:   ProcessSoundFlags
  1074.  *
  1075.  *PARAMETERS:
  1076.  *    lpShip: Points to a ship structure (originally retrieved from
  1077.  *            GetPlayerData) in RenderPlayer.
  1078.  *
  1079.  *NOTES:      All y-coordinates must be made negative, because the
  1080.  *            3D Sound API's use an opposite coordinate system than
  1081.  *            the screen.
  1082.  */
  1083. void ProcessSoundFlags(LPSHIP lpShip)
  1084. {
  1085.     int i;
  1086.     BOOL bStart[MAX_SOUNDS]; //flags, used so we can 
  1087.     BOOL bStop [MAX_SOUNDS];
  1088.  
  1089.     if (!gbSoundInitialized)
  1090.         return;
  1091.  
  1092.     //if one is NULL, so are the other ones and we aren't initialized yet.
  1093.     for (i=0; i<MAX_SOUNDS; i++)
  1094.     {
  1095.         if (lpShip->lpDirectSoundBuffer[i]==NULL)
  1096.             return;
  1097.     }
  1098.  
  1099.     //set all our temporary flags to FALSE.
  1100.     for (i=0; i<MAX_SOUNDS; i++)
  1101.     {
  1102.         bStart[i] = FALSE;
  1103.         bStop[i]  = FALSE;
  1104.     }
  1105.  
  1106.     if (lpShip->dwKeys & KEY_ENGINEOFF)
  1107.         {
  1108.         bStop[SENGINE] = TRUE;
  1109.         lpShip->bEngineRunning = FALSE;
  1110.         }
  1111.  
  1112.     if (lpShip->dwKeys & (KEY_UP | KEY_DOWN))
  1113.         {
  1114.         if (!lpShip->bEngineRunning) //turn on engine
  1115.             {
  1116.             bStart[SENGINE] = TRUE;
  1117.             if (!lpShip->bMoving)   //"fire-up-engine" sound
  1118.                 {
  1119.                 bStart[SSTART] = TRUE;
  1120.                 IDirectSound3DBuffer_SetPosition(lpShip->lpDirectSound3DBuffer[SSTART],
  1121.                                                   P2M(lpShip->dPosX - 320),
  1122.                                                  -P2M(lpShip->dPosY - 240),
  1123.                                                  D3DVAL(0),
  1124.                                                  DS3D_DEFERRED);
  1125.                 bStart[SSTART] = TRUE;
  1126.                 lpShip->bMoving = TRUE;
  1127.                 }
  1128.             lpShip->bEngineRunning = TRUE;
  1129.             }
  1130.         }
  1131.  
  1132.     if (lpShip->bMoving)
  1133.         {
  1134.         IDirectSound3DBuffer_SetPosition(lpShip->lpDirectSound3DBuffer[SENGINE],
  1135.                                          P2M(lpShip->dPosX - 320),
  1136.                                         -P2M(lpShip->dPosY - 240),
  1137.                                         D3DVAL(0),
  1138.                                         DS3D_DEFERRED);
  1139.         IDirectSound3DBuffer_SetVelocity(lpShip->lpDirectSound3DBuffer[SENGINE],
  1140.                                          D3DVAL(lpShip->dVelX * 10), //exagerater vel
  1141.                                          D3DVAL(lpShip->dVelY * 10),
  1142.                                          D3DVAL(0),
  1143.                                          DS3D_DEFERRED);
  1144.         }
  1145.  
  1146.     if (lpShip->dwKeys & KEY_STOP)
  1147.         {
  1148.         if (lpShip->bMoving)
  1149.             {
  1150.             IDirectSound3DBuffer_SetPosition(lpShip->lpDirectSound3DBuffer[SSTOP],
  1151.                                               P2M(lpShip->dPosX - 320),
  1152.                                              -P2M(lpShip->dPosY - 240),
  1153.                                              D3DVAL(0),
  1154.                                              DS3D_DEFERRED);
  1155.             bStart[SSTOP]   = TRUE;
  1156.             bStop[SENGINE]  = TRUE;
  1157.             lpShip->bEngineRunning  = FALSE;
  1158.             lpShip->bMoving         = FALSE;
  1159.             }
  1160.         }
  1161.  
  1162.     if (lpShip->dwKeys & KEY_FIRE)
  1163.         {
  1164.         if (!lpShip->bFiring)
  1165.             {
  1166.             IDirectSound3DBuffer_SetPosition(lpShip->lpDirectSound3DBuffer[BFIRE],
  1167.                                               P2M(lpShip->dPosX - 320),
  1168.                                              -P2M(lpShip->dPosY - 240),
  1169.                                              D3DVAL(0),
  1170.                                              DS3D_DEFERRED);
  1171.             bStart[BFIRE]   = TRUE;
  1172.             lpShip->bFiring = TRUE;
  1173.             }
  1174.         }
  1175.  
  1176.     if (lpShip->bBlockHit)
  1177.         {
  1178.         IDirectSound3DBuffer_SetPosition(lpShip->lpDirectSound3DBuffer[LBOOM],
  1179.  
  1180.                                           P2M(lpShip->dBulletPosX - 320),
  1181.                                          -P2M(lpShip->dBulletPosY - 240),
  1182.                                          D3DVAL(0),
  1183.                                          DS3D_DEFERRED);
  1184.  
  1185.         bStart[LBOOM] = TRUE;
  1186.         lpShip->bBlockHit = FALSE;
  1187.         }
  1188.  
  1189.     if (lpShip->bBounced)
  1190.         {
  1191.         IDirectSound3DBuffer_SetPosition(lpShip->lpDirectSound3DBuffer[SBOUNCE],
  1192.                                          P2M(lpShip->dPosX - 320),
  1193.                                          -P2M(lpShip->dPosY - 240),
  1194.                                          D3DVAL(0),
  1195.                                          DS3D_DEFERRED);
  1196.  
  1197.         bStart[SBOUNCE] = TRUE;
  1198.         lpShip->bBounced = FALSE;
  1199.         }
  1200.  
  1201.  
  1202.     if (lpShip->bDeath)
  1203.         {
  1204.         bStop [BFIRE]   = TRUE;
  1205.         bStop [SBOUNCE] = TRUE;
  1206.         bStop [SSTOP]   = TRUE;
  1207.         bStop [SSTART]  = TRUE;
  1208.         bStop [SENGINE] = TRUE;
  1209.         bStart[SBOOM]   = TRUE; 
  1210.         lpShip->bDeath  = FALSE;  //turn off sound flag.
  1211.         }
  1212.  
  1213.     //stop, update, and start sounds.
  1214.     for (i=0; i<MAX_SOUNDS; i++)
  1215.         {
  1216.         if (bStop[i])
  1217.             {
  1218.             IDirectSoundBuffer_Stop(lpShip->lpDirectSoundBuffer[i]);
  1219.             bStart[i] = FALSE;
  1220.             }
  1221.         }
  1222.     IDirectSound3DListener_CommitDeferredSettings(glpDirectSound3DListener);
  1223.  
  1224.     for (i=0; i<MAX_SOUNDS; i++)
  1225.         {
  1226.         if (bStart[i])
  1227.             {
  1228.              IDirectSoundBuffer_SetCurrentPosition(lpShip->lpDirectSoundBuffer[i], 0);
  1229.  
  1230.              if (DSERR_BUFFERLOST==IDirectSoundBuffer_Play(lpShip->lpDirectSoundBuffer[i],
  1231.                                                            0,
  1232.                                                            0,
  1233.                                                            (i==SENGINE) ? DSBPLAY_LOOPING : 0))
  1234.                 {
  1235.                 WaveReload(gSoundEffect[i]);
  1236.                 }
  1237.             }
  1238.         }
  1239.     lpShip->dwKeys = 0;
  1240. };
  1241.  
  1242.  
  1243.  
  1244.  
  1245. /*
  1246.  * RenderPlayerCB
  1247.  *
  1248.  * Renders a ship in its current state. Also checks if we hit the ship and informs
  1249.  * the ship that it has been destroyed.
  1250.   */
  1251.  
  1252. BOOL WINAPI RenderPlayerCB(DPID dpId, DWORD dwPlayerType, LPCDPNAME lpName, 
  1253.     DWORD dwFlags, LPVOID lpContext)
  1254. {
  1255.     SHIP ship, ourShip;
  1256.     DWORD dwSize = sizeof(ship);
  1257.     BOOL bHit = FALSE;
  1258.     HRESULT hr;
  1259.     DWORD dwTickCount;
  1260.     
  1261.     // get ship data
  1262.     hr = DPlayGetPlayerData(dpId, &ship, &dwSize, DPGET_LOCAL);
  1263.  
  1264.     if (FAILED(hr))
  1265.     {
  1266.         wsprintf(gDebugBuff, TEXT("Get Player local data failed for id %d\n"), dpId);
  1267.         DEBUG_OUT(gDebugBuff);
  1268.         goto FAIL;
  1269.     }
  1270.  
  1271.     // no player data yet
  1272.     if (0 == dwSize)
  1273.         return TRUE; 
  1274.  
  1275.     // ignore current ship ?
  1276.     if (ship.bIgnore)
  1277.     {
  1278.         // if this ship was being ignored, update ignore time-out
  1279.         // A time-out is used here to ensure that this ship doesn't get ignored
  1280.         // forever on our screen in case the destroy message was dropped.
  1281.         dwTickCount = timeGetTime();
  1282.         ship.iCountDown -= dwTickCount - ship.dwLastTick;
  1283.         ship.dwLastTick = dwTickCount;
  1284.         if( ship.iCountDown < 0 ) 
  1285.         {
  1286.             ship.bIgnore = FALSE;
  1287.         }
  1288.  
  1289.         // save ship data
  1290.         hr = DPlaySetPlayerData(dpId, &ship, sizeof(ship), DPSET_LOCAL);
  1291.         if (FAILED(hr))
  1292.         {
  1293.             ShowError(IDS_DPLAY_ERROR_SPLD);
  1294.             goto FAIL;
  1295.         }
  1296.         // we are ignoring this ship, so just bail
  1297.         return TRUE;
  1298.     }
  1299.  
  1300.     // bail, if ship is disabled
  1301.     if (!ship.bEnable) return TRUE;
  1302.  
  1303.     // update ship's position
  1304.     UpdatePosition(dpId, &ship);
  1305.  
  1306.     // get our player data to compare with others
  1307.     dwSize = sizeof(ship);
  1308.     hr = DPlayGetPlayerData(gOurID, &ourShip, &dwSize, DPGET_LOCAL);
  1309.     if (FAILED(hr))
  1310.     {
  1311.         wsprintf(gDebugBuff, TEXT("Get Player local data failed for id %d\n"), dpId);
  1312.         DEBUG_OUT(gDebugBuff);
  1313.         goto FAIL;
  1314.     }
  1315.  
  1316.     // check if our bullet hit the current ship
  1317.     if((dpId != gOurID) && ourShip.bBulletEnable && ship.bEnable)
  1318.     {
  1319.         if( (ourShip.dBulletPosX > ship.dPosX) &&
  1320.             (ourShip.dBulletPosX < (ship.dPosX + 32.0) ) &&
  1321.             (ourShip.dBulletPosY > ship.dPosY) &&
  1322.             (ourShip.dBulletPosY < (ship.dPosY + 32.0) ) )
  1323.         {
  1324.             // hasta-la-vista baby
  1325.             DestroyShip(&ship);
  1326.             // we nailed it
  1327.             bHit = TRUE;
  1328.             // turn off ship locally
  1329.             ship.bEnable = FALSE;
  1330.             // temporarily ignore ship until we get a response
  1331.             ship.bIgnore = TRUE;
  1332.             // set its ignore time-out
  1333.             ship.iCountDown = HIDE_TIMEOUT;
  1334.             // time-stamp
  1335.             ship.dwLastTick = timeGetTime();
  1336.             // turn our bullet off
  1337.             ship.bBulletEnable = FALSE;
  1338.             // update our score
  1339.             ourShip.dwScore += 1000;
  1340.             // save our score
  1341.             hr = DPlaySetPlayerData(gOurID, &ourShip, sizeof(ourShip), DPSET_LOCAL);
  1342.             if (FAILED(hr))
  1343.             {
  1344.                 ShowError(IDS_DPLAY_ERROR_SPLD);
  1345.                 goto FAIL;
  1346.             }
  1347.         }
  1348.     }
  1349.  
  1350.     // render the ship
  1351.     if (ship.bBulletEnable) DrawBullet(&ship);
  1352.     if (ship.bEnable)       DrawShip(&ship);
  1353.  
  1354.     ProcessSoundFlags(&ship);
  1355.  
  1356.     // save ship data
  1357.     hr = DPlaySetPlayerData(dpId, &ship, sizeof(ship), DPSET_LOCAL);
  1358.     if (FAILED(hr))
  1359.     {
  1360.         ShowError(IDS_DPLAY_ERROR_SPLD);
  1361.         goto FAIL;
  1362.     }
  1363.  
  1364.     // inform the player
  1365.     if (bHit)
  1366.     {
  1367.         gShipHitMsg.Id = dpId;
  1368.         SendGameMessage((LPGENERICMSG) &gShipHitMsg, dpId);
  1369.     }
  1370.  
  1371.     // success
  1372.     return TRUE;
  1373.  
  1374. FAIL:
  1375.     // failed
  1376.     return FALSE;
  1377. }
  1378.  
  1379. /*
  1380.  * DrawScreen
  1381.  * 
  1382.  * Renders the current frame
  1383.  */
  1384. BOOL DrawScreen( void )
  1385. {
  1386.     BYTE    mask, col;
  1387.     int     x, y;
  1388.     HRESULT hr;
  1389.  
  1390.     // clear screen
  1391.     EraseScreen();
  1392.     
  1393.     // render players
  1394.     hr = DPlayEnumPlayers(NULL, RenderPlayerCB, NULL, 0);
  1395.     if (FAILED(hr))
  1396.     {
  1397.         ShowError(IDS_DPLAY_ERROR_EP);
  1398.         goto FAIL;
  1399.     }
  1400.  
  1401.     // render field
  1402.     for( y=0; y<30; y++)
  1403.     {
  1404.         for( x=0; x<40; x++)
  1405.         {
  1406.             mask = 1 << (x & 0x7);
  1407.             col = x >> 3;
  1408.             if( gBlocks.bits[y][col] & mask )
  1409.                 DrawBlock( x, y );
  1410.         }
  1411.     }
  1412.     
  1413.     // render score
  1414.     if (!DrawScore())
  1415.     {
  1416.         goto FAIL;
  1417.     }
  1418.  
  1419.     // render fragments
  1420.     DrawFragments();    
  1421.  
  1422.     // render frame rate
  1423.     if( gbShowFrameCount )
  1424.         DisplayFrameRate();
  1425.  
  1426.     // show
  1427.     FlipScreen();
  1428.  
  1429.     // success
  1430.     return TRUE;
  1431.  
  1432. FAIL:
  1433.     return FALSE;
  1434. }
  1435.  
  1436. /*
  1437.  * DisplayFrameRate
  1438.  * 
  1439.  * Renders current frame rate
  1440.  */
  1441. void DisplayFrameRate( void )
  1442. {
  1443.     DWORD           time2;
  1444.     char            buff[256];
  1445.     static DWORD    dwFrames;
  1446.     
  1447.     gdwFrameCount++;
  1448.     time2 = timeGetTime() - gdwFrameTime;
  1449.     if( time2 > 1000 )
  1450.     {
  1451.         dwFrames = (gdwFrameCount*1000)/time2;
  1452.         gdwFrameTime = timeGetTime();
  1453.         gdwFrameCount = 0;
  1454.     }
  1455.     if( dwFrames == 0 )
  1456.     {
  1457.         return;
  1458.     }
  1459.  
  1460.     if (dwFrames != gdwFramesLast)
  1461.     {
  1462.         gdwFramesLast = dwFrames;
  1463.     }
  1464.  
  1465.     if( dwFrames > 99 )
  1466.     {
  1467.     dwFrames = 99;
  1468.     }
  1469.     buff[0] = (char)((dwFrames / 10) + '0');
  1470.     buff[1] = (char)((dwFrames % 10) + '0');
  1471.     buff[2] = '\0';
  1472.     bltScore(buff, 295, 10);
  1473. }
  1474.  
  1475. /*
  1476.  * DrawScore
  1477.  *
  1478.  * Renders our current score
  1479.  */
  1480. BOOL DrawScore( void )
  1481. {
  1482.     SHIP        ship;
  1483.     DWORD       dwSize;
  1484.     char        dwScorebuf[11];
  1485.     int         rem;
  1486.     HRESULT     hr;
  1487.  
  1488.     dwSize = sizeof(ship);
  1489.     hr = DPlayGetPlayerData(gOurID, &ship, &dwSize, DPGET_LOCAL);
  1490.     if (FAILED(hr))
  1491.     {
  1492.         wsprintf(gDebugBuff, TEXT("Get Player local data failed for id %d\n"), gOurID);
  1493.         DEBUG_OUT(gDebugBuff);
  1494.         goto FAIL;
  1495.     }
  1496.  
  1497.     // blt everything in reverse order if we are doing destination transparency
  1498.     // calculate dwScore string
  1499.     dwScorebuf[0] = (BYTE)ship.dwScore/100000 + '0';
  1500.     rem = ship.dwScore % 100000;
  1501.     dwScorebuf[1] = rem/10000 + '0';
  1502.     rem = ship.dwScore % 10000;
  1503.     dwScorebuf[2] = rem/1000 + '0';
  1504.     rem = ship.dwScore % 1000;
  1505.     dwScorebuf[3] = rem/100 + '0';
  1506.     rem = ship.dwScore % 100;
  1507.     dwScorebuf[4] = rem/10 + '0';
  1508.     rem = ship.dwScore % 10;
  1509.     dwScorebuf[5] = rem + '0';
  1510.     dwScorebuf[6] = '\0';
  1511.  
  1512.     bltScore(dwScorebuf, 8, 8);
  1513.  
  1514.     // save ship data
  1515.     hr = DPlaySetPlayerData(gOurID, &ship, sizeof(ship), DPSET_LOCAL);
  1516.     if (FAILED(hr))
  1517.     {
  1518.         ShowError(IDS_DPLAY_ERROR_SPLD);
  1519.         goto FAIL;
  1520.     }
  1521.  
  1522.     return TRUE;
  1523.  
  1524. FAIL:
  1525.     // failed
  1526.     return FALSE;
  1527. }
  1528.  
  1529. /*
  1530.  * DrawBlock
  1531.  *
  1532.  * Renders a block
  1533.  */
  1534. void DrawBlock( int x, int y )
  1535. {
  1536.     RECT    src;
  1537.     
  1538.     src.top = 0;
  1539.     src.left = 224;
  1540.     src.right = src.left + 16;
  1541.     src.bottom = src.top + 16;
  1542.     bltObject( x << 4, y << 4, glpNum, &src, DDBLTFAST_SRCCOLORKEY );
  1543. }
  1544.  
  1545. /*
  1546.  * DrawShip
  1547.  *
  1548.  * Renders a ship
  1549.  */
  1550. void DrawShip( LPSHIP lpShip )
  1551. {
  1552.     RECT    src;
  1553.     LPDIRECTDRAWSURFACE surf;
  1554.  
  1555.     src.top = 32 * (lpShip->cFrame / 10 );
  1556.     src.left = 32 * (lpShip->cFrame % 10 );
  1557.     src.right = src.left + 32;
  1558.     src.bottom = src.top + 32;
  1559.     switch( lpShip->byType )
  1560.     {
  1561.     case 0: surf = glpShip0; break;
  1562.     case 1: surf = glpShip1; break;
  1563.     case 2: surf = glpShip2; break;
  1564.     case 3: surf = glpShip3; break;
  1565.     default: DEBUG_OUT(TEXT("Ship type not specified\n")); return;
  1566.     }
  1567.     bltObject((int)lpShip->dPosX, (int)lpShip->dPosY, surf, &src, DDBLTFAST_SRCCOLORKEY );
  1568. }
  1569.  
  1570. /*
  1571.  * DrawBullet
  1572.  *
  1573.  * Renders a bullet 
  1574.  */
  1575. void DrawBullet( LPSHIP lpShip )
  1576. {
  1577.     RECT    src;
  1578.     
  1579.     src.top = BULLET_Y;
  1580.     src.left = BULLET_X + (lpShip->byType)*4;
  1581.     src.right = src.left + 3;
  1582.     src.bottom = src.top + 3;
  1583.     bltObject((int)lpShip->dBulletPosX, (int)lpShip->dBulletPosY, glpNum, &src, DDBLTFAST_SRCCOLORKEY );
  1584. }
  1585.  
  1586. /*
  1587.  * DrawFragments
  1588.  *
  1589.  * Renders the fragments
  1590.  */
  1591.  
  1592. void DrawFragments( void )
  1593. {
  1594.     int     i;
  1595.     
  1596.     for(i=0; i<64; i++)
  1597.     {
  1598.         if( gFrags[i].valid )
  1599.         {
  1600.             bltObject((int)gFrags[i].dPosX, (int)gFrags[i].dPosY, gFrags[i].surf,
  1601.                 &(gFrags[i].src), DDBLTFAST_SRCCOLORKEY );
  1602.         }
  1603.     }
  1604. }
  1605.  
  1606. /*
  1607.  * ReceiveGameMessages
  1608.  *
  1609.  * Checks if there are any messages for us and receives them
  1610.  */
  1611. HRESULT ReceiveMessages( void )
  1612. {
  1613.     DPID                idFrom, idTo;
  1614.     LPVOID              lpvMsgBuffer;
  1615.     DWORD               dwMsgBufferSize;
  1616.     HRESULT             hr;
  1617.  
  1618.     // read all messages in queue
  1619.     dwMsgBufferSize = gdwReceiveBufferSize;
  1620.     lpvMsgBuffer = glpvReceiveBuffer;
  1621.     
  1622.     while (TRUE)
  1623.     {
  1624.         // see what's out there
  1625.         idFrom = 0;
  1626.         idTo = 0;
  1627.  
  1628.         hr = DPlayReceive(&idFrom, &idTo, DPRECEIVE_ALL, lpvMsgBuffer, &dwMsgBufferSize);
  1629.         if (hr == DPERR_BUFFERTOOSMALL)
  1630.         {
  1631.             if (lpvMsgBuffer == NULL)
  1632.             {
  1633.                 lpvMsgBuffer = GlobalAllocPtr(GHND, dwMsgBufferSize);
  1634.                 if (lpvMsgBuffer == NULL)
  1635.                     return (DPERR_NOMEMORY);
  1636.                 glpvReceiveBuffer = lpvMsgBuffer;
  1637.                 gdwReceiveBufferSize = dwMsgBufferSize;
  1638.             }
  1639.             else if (dwMsgBufferSize > gdwReceiveBufferSize)
  1640.             {
  1641.                 lpvMsgBuffer = GlobalReAllocPtr(lpvMsgBuffer, dwMsgBufferSize, 0);
  1642.                 if (lpvMsgBuffer == NULL)
  1643.                     return (DPERR_NOMEMORY);
  1644.                 glpvReceiveBuffer = lpvMsgBuffer;
  1645.                 gdwReceiveBufferSize = dwMsgBufferSize;
  1646.             }
  1647.         }
  1648.         else if ((hr == DP_OK) && 
  1649.                  ((dwMsgBufferSize >= sizeof(GENERICMSG)) || 
  1650.                   (dwMsgBufferSize >= sizeof(DPMSG_GENERIC))))
  1651.         {
  1652.             if (idFrom == DPID_SYSMSG)
  1653.             {
  1654.                 DoSystemMessage((LPDPMSG_GENERIC) lpvMsgBuffer, dwMsgBufferSize, idFrom, idTo);
  1655.             }
  1656.             else
  1657.             {
  1658.                 DoApplicationMessage((LPGENERICMSG) lpvMsgBuffer, dwMsgBufferSize, idFrom, idTo);
  1659.             }
  1660.         }
  1661.         else
  1662.             break;
  1663.     };
  1664.  
  1665.     return hr;
  1666. }
  1667.  
  1668. /*
  1669.  * DoSystemMessage
  1670.  *
  1671.  * Evaluates system messages and performs appropriate actions
  1672.  */
  1673. void DoSystemMessage( LPDPMSG_GENERIC lpMsg, DWORD dwMsgSize, DPID idFrom, DPID idTo )
  1674. {
  1675.     switch( lpMsg->dwType)
  1676.     {
  1677.     case DPSYS_CREATEPLAYERORGROUP:
  1678.         {
  1679.             LPDPMSG_CREATEPLAYERORGROUP lpAddMsg = (LPDPMSG_CREATEPLAYERORGROUP) lpMsg;
  1680.  
  1681.             if( gbIsHost)
  1682.             {
  1683.                 gHostMsg.Blocks = gBlocks;
  1684.                 SendGameMessage((LPGENERICMSG) &gHostMsg, lpAddMsg->dpId);
  1685.             }
  1686.         }
  1687.         break;
  1688.  
  1689.     case DPSYS_DESTROYPLAYERORGROUP:
  1690.         {
  1691.             LPSHIP lpShip;
  1692.             LPDPMSG_DESTROYPLAYERORGROUP lpDestroyMsg = (LPDPMSG_DESTROYPLAYERORGROUP) lpMsg;
  1693.  
  1694.             if ((sizeof(SHIP) != lpDestroyMsg->dwLocalDataSize) || 
  1695.                 (NULL == lpDestroyMsg->lpLocalData))
  1696.                 break;
  1697.  
  1698.             lpShip = lpDestroyMsg->lpLocalData;
  1699.             ReleasePlayerLocalSoundData(lpShip);
  1700.         }
  1701.         break;
  1702.  
  1703.     case DPSYS_HOST:
  1704.         {           
  1705.             gbIsHost = TRUE;            
  1706.             UpdateTitle();
  1707.         }
  1708.  
  1709.         break;
  1710.  
  1711.     case DPSYS_SESSIONLOST:
  1712.         // inform user that session was lost
  1713.         ShowError(IDS_DPLAY_ERROR_SL);
  1714.         gbSessionLost = TRUE;
  1715.         break;
  1716.     }
  1717. }
  1718.  
  1719. /*
  1720.  * DoApplicationMessage
  1721.  *
  1722.  * Evaluates an application message and performs appropriate actions
  1723.  */
  1724. void DoApplicationMessage( LPGENERICMSG lpMsg, DWORD dwMsgSize, DPID idFrom, DPID idTo )
  1725. {        
  1726.     HRESULT hr;
  1727.  
  1728.     switch( lpMsg->byType )
  1729.     {
  1730.     case MSG_HOST:
  1731.         {
  1732.             LPHOSTMSG       lpHost;
  1733.  
  1734.             if( !gbIsHost )
  1735.             {
  1736.                 lpHost = (LPHOSTMSG) lpMsg;
  1737.                 // receive the field layout
  1738.                 gBlocks = lpHost->Blocks;
  1739.  
  1740.                 // have host initializtion at this point
  1741.                 gbHaveHostInit = TRUE;
  1742.                 
  1743.                 // start updating screen
  1744.                 gbIsActive = TRUE;
  1745.             }
  1746.         }
  1747.         break;
  1748.  
  1749.     case MSG_BLOCKHIT:
  1750.         {
  1751.             LPBLOCKHITMSG   lpBlockHit;
  1752.  
  1753.             lpBlockHit = (LPBLOCKHITMSG) lpMsg;
  1754.             gBlocks.bits[lpBlockHit->byRow][lpBlockHit->byCol] &= ~lpBlockHit->byMask;
  1755.         }
  1756.         break;
  1757.  
  1758.     case MSG_ADDBLOCK:
  1759.         {
  1760.             LPADDBLOCKMSG   lpAddBlock;
  1761.  
  1762.             lpAddBlock = (LPADDBLOCKMSG) lpMsg;
  1763.             setBlock( lpAddBlock->byX, lpAddBlock->byY);
  1764.         }
  1765.         break;
  1766.  
  1767.     case MSG_SHIPHIT:
  1768.         {
  1769.             LPSHIPHITMSG    lpShipHit = (LPSHIPHITMSG) lpMsg;
  1770.             SHIP ship;
  1771.             DWORD dwSize;
  1772.  
  1773.             dwSize = sizeof(SHIP);
  1774.              // get player local data
  1775.             hr = DPlayGetPlayerData(lpShipHit->Id, &ship, &dwSize, DPGET_LOCAL);
  1776.             if (FAILED(hr))
  1777.                 return;
  1778.  
  1779.             // no player data yet
  1780.             if (0 == dwSize)
  1781.                 return;
  1782.  
  1783.             if (!ship.bIgnore) 
  1784.             {
  1785.                 // explode the ship on our screen
  1786.                 DestroyShip(&ship);
  1787.  
  1788.                 // turn it off
  1789.                 ship.bEnable = FALSE;
  1790.                 ship.bBulletEnable = FALSE;
  1791.  
  1792.                 // if it is us
  1793.                 if (lpShipHit->Id == gOurID)
  1794.                 {
  1795.                     // set our hide time-out
  1796.                     ship.iCountDown = HIDE_TIMEOUT;
  1797.                     ship.dwLastTick = timeGetTime();
  1798.                     // let the world know that we are dead
  1799.                     gShipHitMsg.Id = gOurID;
  1800.                     SendGameMessage((LPGENERICMSG) &gShipHitMsg, DPID_ALLPLAYERS);                  
  1801.                 }
  1802.             }
  1803.             // update player local data
  1804.             DPlaySetPlayerData(lpShipHit->Id, &ship, sizeof(ship), DPSET_LOCAL);
  1805.         }
  1806.         break;
  1807.  
  1808.     case MSG_CONTROL:
  1809.         {
  1810.             LPCONTROLMSG lpControlMsg;
  1811.             SHIP ship;
  1812.             DWORD dwSize;
  1813.  
  1814.             lpControlMsg = (LPCONTROLMSG) lpMsg;
  1815.             dwSize = sizeof(SHIP);
  1816.             // get player local data
  1817.             hr = DPlayGetPlayerData(idFrom, &ship, &dwSize, DPGET_LOCAL);
  1818.             if (FAILED(hr))
  1819.                 return;
  1820.  
  1821.             // no player data yet
  1822.             if (0 == dwSize)
  1823.                 return;
  1824.  
  1825.             // update its State
  1826.             UpdateState(&ship, (DWORD)lpControlMsg->byState);
  1827.  
  1828.             // save it back
  1829.             DPlaySetPlayerData(idFrom, &ship, dwSize, DPSET_LOCAL);
  1830.         }
  1831.         break;
  1832.  
  1833.     case MSG_SYNC:
  1834.         {
  1835.             LPSYNCMSG lpSyncMsg;
  1836.             SHIP ship;
  1837.             DWORD dwSize;
  1838.  
  1839.             lpSyncMsg = (LPSYNCMSG) lpMsg;
  1840.             dwSize = sizeof(SHIP);
  1841.             // get player local data
  1842.             hr = DPlayGetPlayerData(idFrom, &ship, &dwSize, DPGET_LOCAL);
  1843.             if (FAILED(hr))
  1844.                 return;
  1845.  
  1846.             // we are seeing this player for the first time
  1847.             // so do the initialization
  1848.             if (0 == dwSize)
  1849.             {
  1850.                 ZeroMemory(&ship, sizeof(ship));
  1851.  
  1852.                 // initialize sound buffers
  1853.                 InitPlayerLocalSoundData(&ship);
  1854.  
  1855.                 ship.byType = lpSyncMsg->byShipType;
  1856.                 ship.dPosX = lpSyncMsg->dPosX;
  1857.                 ship.dPosY = lpSyncMsg->dPosY;
  1858.                 ship.cFrame = lpSyncMsg->cFrame;
  1859.                 ship.dwLastTick = timeGetTime();
  1860.                 ship.bEnable = TRUE;
  1861.             }
  1862.             
  1863.             if (ship.bEnable)
  1864.             {
  1865.                 // head towards rendezvous location (accelerate/decelerate as necessary)
  1866.                 ship.dVelX = (lpSyncMsg->dPosX - ship.dPosX)/1000;
  1867.                 ship.dVelY = (lpSyncMsg->dPosY - ship.dPosY)/1000;
  1868.                 ship.cFrame = lpSyncMsg->cFrame;
  1869.             }
  1870.             else if (!ship.bIgnore)
  1871.             // Ship is alive, but we just don't know it.
  1872.             // So, display it at the rendezvous location.
  1873.             {
  1874.                 ship.dPosX = lpSyncMsg->dPosX;
  1875.                 ship.dPosY = lpSyncMsg->dPosY;
  1876.                 ship.cFrame = lpSyncMsg->cFrame;
  1877.                 ship.dwLastTick = timeGetTime();
  1878.                 ship.bEnable = TRUE;
  1879.             }
  1880.  
  1881.             // save it back
  1882.             DPlaySetPlayerData(idFrom, &ship, sizeof(ship), DPSET_LOCAL);
  1883.         }
  1884.         break;
  1885.  
  1886.     default:
  1887.         {
  1888.             wsprintf(gDebugBuff, TEXT("Unknown message type %d\n"), lpMsg->byType);
  1889.             DEBUG_OUT( gDebugBuff );
  1890.         }
  1891.         break;
  1892.     }
  1893. }
  1894.  
  1895. /*
  1896.  * SendGameMessage
  1897.  *
  1898.  * Sends a message to specified player(s)
  1899.  */
  1900. void SendGameMessage( LPGENERICMSG lpMsg, DPID idTo )
  1901. {
  1902.     int             nBytes;
  1903.     DWORD           dwFlags = 0;
  1904.  
  1905.     if (gbSessionLost)
  1906.     {
  1907.         // no sends when we are not in the session
  1908.         return;
  1909.     }
  1910.  
  1911.     switch( lpMsg->byType )
  1912.     {
  1913.     case MSG_HOST:
  1914.         nBytes = sizeof( HOSTMSG );
  1915.         dwFlags = DPSEND_GUARANTEED;
  1916.         break;
  1917.  
  1918.     case MSG_BLOCKHIT:
  1919.         nBytes = sizeof( BLOCKHITMSG );
  1920.         break;
  1921.  
  1922.     case MSG_SHIPHIT:
  1923.         nBytes = sizeof( SHIPHITMSG );
  1924.         break;
  1925.  
  1926.     case MSG_ADDBLOCK:
  1927.         nBytes = sizeof( ADDBLOCKMSG );
  1928.         break;
  1929.  
  1930.     case MSG_CONTROL:
  1931.         nBytes = sizeof( CONTROLMSG );
  1932.         break;
  1933.  
  1934.     case MSG_SYNC:
  1935.         nBytes = sizeof( SYNCMSG );
  1936.         break;
  1937.  
  1938.     default:
  1939.         return;
  1940.     }
  1941.  
  1942.     if (gbReliable)
  1943.     {
  1944.         dwFlags = DPSEND_GUARANTEED;
  1945.     }
  1946.  
  1947.     // Send the message to the relevant player(s)
  1948.     DPlaySend(gOurID, idTo, dwFlags, (LPVOID)lpMsg, nBytes);    
  1949. }
  1950.  
  1951. /*
  1952.  * CleanupComm
  1953.  *
  1954.  * Cleans up communication stuff
  1955.  */
  1956. void CleanupComm(void)
  1957. {
  1958.     HRESULT hr;
  1959.  
  1960.     //free up all the local sound buffers
  1961.     ReleaseLocalData();
  1962.  
  1963.     // free the receive buffer
  1964.     if (glpvReceiveBuffer)
  1965.     {
  1966.         GlobalFreePtr(glpvReceiveBuffer);
  1967.         glpvReceiveBuffer = NULL;
  1968.     }
  1969.  
  1970.     // delete our player
  1971.     if( gOurID ) 
  1972.     {
  1973.         hr = DPlayDestroyPlayer(gOurID);
  1974.         if (FAILED(hr))
  1975.         {
  1976.             ShowError(IDS_DPLAY_ERROR_DP);
  1977.         }
  1978.         gOurID = 0;
  1979.     }
  1980.  
  1981.     // cleanup directplay objects
  1982.     hr = DPlayClose();
  1983.     hr = DPlayRelease();
  1984. }
  1985.  
  1986.